﻿using Oracle.ManagedDataAccess.Client;
using System;
using System.Collections.Generic;
using System.Text;
using UPos.Core.DataDriver;
using UPos.Core.Entity;
using UPos.Core.LogProvider;
using UPos.Core.RecordProvider;

namespace UPos.Core.SaleProvider
{
    public class EASSales
    {
        #region SQLs

        #region SALES
        static string SALES =
        @"Select
a.fid FID
, a.fbizdate BizDate
, a.cfmachineno MachineNo
, a.fnumber BillNumber
, u.fnumber CreaterNumber
, u.fname_l2 CreaterName
, sum(b.cfamount) Amount
, a.cfpaymentmoney Paymentmoney
FROM CT_BIL_RetailPos A 
JOIN Ct_Bil_Retailposentry b on a.fid = b.fparentid
join T_PM_User u on u.fid = a.fcreatorid
where a.cfstorageid = :shopfid
and to_char(a.fbizdate, 'yyyy-mm-dd') = :saledate
[upedFidWhere]
group by 
a.fid
, a.fbizdate 
, a.cfmachineno 
, a.fnumber 
, u.fnumber 
, u.fname_l2
, a.cfpaymentmoney
order by a.fid";
        #endregion

        #region SALEITEMS
        static string SALEITEMS =
        @"Select 
b.fparentid FParentID
, e.fnumber ""Number""
, b.cfamount Qty
, b.cfagio_sum_price TotalPrice
FROM CT_BIL_RetailPosEntry B 
JOIN T_BD_Material E ON B.CFMaterialID = E.FID
where fparentid in (:parentids)
order by b.fparentid";
        #endregion

        #region RECEIVEITEMS
        static string RECEIVEITEMS = @"
select 
a.fparentid FParentID
, a.Cfhave_pay_money PayMoney
, r.fname_l2 TypeName
, r.fnumber TypeID
from CT_BIL_RetailPRPRE a
join CT_SBA_ShopReceivetype r on a.cfpaymenttype = r.fid
where fparentid in (:parentids)
order by a.fparentid";
        #endregion

        #endregion

        public ShopInfo Shop { get; set; }

        string ShopFID { get { return Shop.ShopFID; } }

        public RecordSQLite Recorder { get; set; }

        public DateTime SaleDate { get; set; }

        DbOracle _oracle;
        DbOracle Oracle
        {
            get
            {
                if (_oracle == null)
                    _oracle = new DbOracle();
                return _oracle;
            }
        }

        public bool NeedUp { get { return GetAllCount() > Recorder.GetUpedCount(); } }

        public EASSales(DateTime date, ShopInfo shopInfo, RecordSQLite recorder)
        {
            SaleDate = date;

            Shop = shopInfo;

            Recorder = recorder;
            recorder.SaleDate = date;
            recorder.ShopFID = Shop.ShopFID;
        }

        public int GetAllCount()
        {
            var count = Oracle.ExecuteScalar(
                "select count(1) from CT_BIL_RetailPos Where to_char(fbizdate, 'yyyy-mm-dd')=:saledate and Cfstorageid=:shopid",
                "saledate".OP(SaleDate.ToString("yyyy-MM-dd")),
                "shopid".OP(ShopFID));

            LogSQLite.Write("EASSales.GetAllCount", "return(" + count + ")");

            return Convert.ToInt32(count);
        }

        public List<Sale> GetNeedUp()
        {
            try
            {
                return GetNeedUpUnSafe();
            }
            catch (Exception e)
            {
                LogSQLite.Write("EASSales.GetNeedUp.Exception", e.Message);
                return null;
            }
        }

        List<Sale> GetNeedUpUnSafe()
        {
            LogSQLite.Write("EASSales.GetNeedUp", "next(Recorder.GetUpedFid)");

            var upedFids = Recorder.GetUpedFid();
            var upedFidWhere = GenerateUpedFidWhere(upedFids);

            LogSQLite.Write("GenerateUpedFidWhere ", "return(" + upedFidWhere + ") next(ExecuteReader const SALES)");

            string sql = SALES.Replace("[upedFidWhere]", upedFidWhere);
            StringBuilder builder = new StringBuilder("'");
            List<Sale> list = new List<Sale>();
            using (OracleDataReader reader = Oracle.ExecuteReader(sql, "shopfid".OP(ShopFID), "saledate".OP(SaleDate.ToString("yyyy-MM-dd"))))
            {
                LogSQLite.Write("ExecuteReader", "({0}) return ({1}) next(Builder List)", sql, reader.HasRows);

                if (!reader.HasRows)
                    return list;

                while (reader.Read())
                {
                    list.Add(new Sale(reader));
                    builder.Append(list[list.Count - 1].FID);
                    builder.Append("','");
                } 
                if (builder.Length >= 4)
                    builder.Remove(builder.Length - 2, 2);
            }

            sql = SALEITEMS.Replace(":parentids", builder.ToString());
            using (OracleDataReader entriesReader = Oracle.ExecuteReader(sql))
            {
                LogSQLite.Write("ExecuteReader", "({0}) return ({1}) next(Builder List)", sql, entriesReader.HasRows);

                int index = 0;
                List<SaleEntry> entries = null;
                string parentid = null;
                while (entriesReader.Read())
                {
                    parentid = entriesReader.GetString(entriesReader.GetOrdinal("FParentID"));
                    if (entries == null || entries[0].FParentID != parentid)
                    {
                        entries = new List<SaleEntry>();
                        list[index].SaleItems = entries;
                        index++;
                    }
                    entries.Add(new SaleEntry(entriesReader));
                }
            }

            sql = RECEIVEITEMS.Replace(":parentids", builder.ToString());
            using (OracleDataReader entriesReader = Oracle.ExecuteReader(sql))
            {
                LogSQLite.Write("ExecuteReader", "({0}) return ({1}) next(Builder List)", sql, entriesReader.HasRows);

                int index = 0;
                List<ReceiveEntries> entries = null;
                string parentid = null;
                while (entriesReader.Read())
                {
                    parentid = entriesReader.GetString(entriesReader.GetOrdinal("FParentID"));
                    if (entries == null || entries[0].FParentID != parentid)
                    {
                        entries = new List<ReceiveEntries>();
                        list[index].ReceiveItems = entries;
                        index++;
                    }
                    entries.Add(new ReceiveEntries(entriesReader, r =>
                    {
                        switch (r.GetString(r.GetOrdinal("TypeID")))
                        {
                            case "001": return "CH"; //现金
                            case "003": return "CI"; //银联
                            default: return "OT";
                        }
                    }));
                }
            }

            LogSQLite.Write("EASSales.GetNeedUp", "return List({0})", list.Count);
            return list;
        }

        string GenerateUpedFidWhere(List<string> upedFids)
        {
            var preWhere = string.Join("' and a.fid <> '", upedFids);
            if (string.IsNullOrWhiteSpace(preWhere))
                return string.Empty;
            else
                return " and a.fid <> '" + preWhere + "'";
        }
    }
}